﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ahp;

namespace AhpTest
{
    [TestClass]
    public class HierarchyTest
    {
        [TestMethod]
        public void InitialStateTest()
        {
            Hierarchy hierarchy1 = new Hierarchy();
            Assert.IsNotNull(hierarchy1.GoalNode, "After Hierarchy object initialized GoalNode property must be initialized with default value");
            Assert.AreEqual("Goal", hierarchy1.GoalNode.Name, "GoalNode default name must be \"Goal\"");

            Hierarchy hierarchy2 = new Hierarchy("Other goal");
            Assert.AreEqual("Other goal", hierarchy2.GoalNode.Name);
        }

        [TestMethod]
        public void AddAlternativeTest()
        {
            Hierarchy hierarchy = new Hierarchy();
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion1"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion2"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion3"));
            hierarchy.GoalNode.CriterionNodes[0].SubcriterionNodes.Add(new CriterionNode("Criterion11"));

            Alternative alternative1 = new Alternative("Alternative1");
            Alternative alternative2 = new Alternative("Alternative2");
            Alternative alternative3 = new Alternative("Alternative3");

            hierarchy.Alternatives.Add(alternative1);
            hierarchy.Alternatives.Add(alternative2);
            hierarchy.Alternatives.Add(alternative3);

            foreach (CriterionNode lowestCriterion in hierarchy.GoalNode.GetLowestCriterionNodes())
            {
                Assert.IsNotNull(lowestCriterion.AlternativeNodes[alternative1]);
                Assert.IsNotNull(lowestCriterion.AlternativeNodes[alternative2]);
                Assert.IsNotNull(lowestCriterion.AlternativeNodes[alternative3]);
            }
        }

        [TestMethod]
        public void RemoveAlternativeTest()
        {
            Hierarchy hierarchy = new Hierarchy();
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion1"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion2"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion3"));
            hierarchy.GoalNode.CriterionNodes[0].SubcriterionNodes.Add(new CriterionNode("Criterion11"));

            Alternative alternative1 = new Alternative("Alternative1");
            Alternative alternative2 = new Alternative("Alternative2");
            Alternative alternative3 = new Alternative("Alternative3");

            hierarchy.Alternatives.Add(alternative1);
            hierarchy.Alternatives.Add(alternative2);
            hierarchy.Alternatives.Add(alternative3);

            foreach (CriterionNode lowestCriterion in hierarchy.GoalNode.GetLowestCriterionNodes())
            {
                Assert.IsNotNull(lowestCriterion.AlternativeNodes[alternative1]);
                Assert.IsNotNull(lowestCriterion.AlternativeNodes[alternative2]);
                Assert.IsNotNull(lowestCriterion.AlternativeNodes[alternative3]);
            }

            hierarchy.Alternatives.Remove(alternative1);
            foreach (CriterionNode lowestCriterion in hierarchy.GoalNode.GetLowestCriterionNodes())
            {
                Assert.IsNull(lowestCriterion.AlternativeNodes[alternative1]);
            }
        }

        [TestMethod]
        public void ClearAlternativeTest()
        {
            Hierarchy hierarchy = new Hierarchy();
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion1"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion2"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion3"));
            hierarchy.GoalNode.CriterionNodes[0].SubcriterionNodes.Add(new CriterionNode("Criterion11"));

            Alternative alternative1 = hierarchy.Alternatives.Add("Alternative1");
            Alternative alternative2 = hierarchy.Alternatives.Add("Alternative2");
            Alternative alternative3 = hierarchy.Alternatives.Add("Alternative3");

            foreach (CriterionNode lowestCriterion in hierarchy.GoalNode.GetLowestCriterionNodes())
            {
                Assert.IsTrue(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative1));
                Assert.IsTrue(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative2));
                Assert.IsTrue(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative3));
            }

            hierarchy.Alternatives.Clear();
            foreach (CriterionNode lowestCriterion in hierarchy.GoalNode.GetLowestCriterionNodes())
            {
                Assert.IsFalse(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative1));
                Assert.IsFalse(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative2));
                Assert.IsFalse(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative3));
            }
        }

        [TestMethod]
        public void RefreshAlternativeNodesTest()
        {
            Hierarchy hierarchy = new Hierarchy();
            Alternative alternative1 = hierarchy.Alternatives.Add("Alternative1");
            Alternative alternative2 = hierarchy.Alternatives.Add("Alternative2");
            Alternative alternative3 = hierarchy.Alternatives.Add("Alternative3");

            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion1"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion2"));
            hierarchy.GoalNode.CriterionNodes.Add(new CriterionNode("Criterion3"));
            CriterionNode criterion11 = hierarchy.GoalNode.CriterionNodes[0].SubcriterionNodes.Add("Criterion11");

            Alternative alternative4 = new Alternative("Alternative4");
            criterion11.AlternativeNodes.Add(new AlternativeNode(alternative4));

            hierarchy.RefreshAlternativeNodes();
            foreach (CriterionNode lowestCriterion in hierarchy.GoalNode.GetLowestCriterionNodes())
            {
                Assert.IsTrue(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative1));
                Assert.IsTrue(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative2));
                Assert.IsTrue(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative3));
                Assert.IsFalse(lowestCriterion.AlternativeNodes.ContainsWithAlternative(alternative4));
            }
        }

        [TestMethod]
        [ExpectedException(typeof(KeyNotFoundException))]
        public void AlternativeNodeIndexerWrongAlternativeKeyTest()
        {
            Hierarchy hierarchy = new Hierarchy();
            CriterionNode criterionNode = hierarchy.GoalNode.CriterionNodes.Add("Criterion");

            AlternativeNode alternativeNode = hierarchy[new Alternative("WrongKey"), criterionNode];
        }

        [TestMethod]
        [ExpectedException(typeof(KeyNotFoundException))]
        public void AlternativeNodeIndexerWrongCriterionKeyTest()
        {
            Hierarchy hierarchy = new Hierarchy();
            Alternative alternative = hierarchy.Alternatives.Add("Alternative");

            AlternativeNode alternativeNode = hierarchy[alternative, new CriterionNode("WrongKey")];
        }

        [TestMethod]
        public void AlternativeNodeIndexerTest()
        {
            Hierarchy hierarchy = new Hierarchy();
            Alternative alternative1 = hierarchy.Alternatives.Add("Alternative1");
            Alternative alternative2 = hierarchy.Alternatives.Add("Alternative2");

            CriterionNode criterion1 = hierarchy.GoalNode.CriterionNodes.Add("Criterion1");
            CriterionNode criterion2 = hierarchy.GoalNode.CriterionNodes.Add("Criterion2");
            CriterionNode criterion11 = hierarchy.GoalNode.CriterionNodes[0].SubcriterionNodes.Add("Criterion11");

            Assert.AreEqual(hierarchy[alternative1, criterion2].Alternative, alternative1);
            Assert.AreEqual(hierarchy[alternative1, criterion2].CriterionNode, criterion2);

            Assert.AreEqual(hierarchy[alternative1, criterion11].Alternative, alternative1);
            Assert.AreEqual(hierarchy[alternative1, criterion11].CriterionNode, criterion11);

            Assert.AreEqual(hierarchy[alternative2, criterion2].Alternative, alternative2);
            Assert.AreEqual(hierarchy[alternative2, criterion2].CriterionNode, criterion2);

            Assert.AreEqual(hierarchy[alternative2, criterion11].Alternative, alternative2);
            Assert.AreEqual(hierarchy[alternative1, criterion11].CriterionNode, criterion11);
        }
    }
}
